/**
*  Copyright (c) 2011, Alex Theodoridis
*  All rights reserved.

*  Redistribution and use in source and binary forms, with 
*  or without modification, are permitted provided that the 
*  following conditions are met:
*  Redistributions of source code must retain the above 
*  copyright notice, this list of conditions and the following disclaimer.
*  Redistributions in binary form must reproduce the above 
*  copyright notice, this list of conditions and the following
*  disclaimer in the documentation and/or other materials 
*  provided with the distribution.

*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS
*  AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
*  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
*  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
*  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
*  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
*  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
*  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
*  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
*  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE,
*  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
*/


#include "NNVar.h"
#include <math.h>
#include <boost/numeric/conversion/cast.hpp>

const unsigned int NNVar::CONST_DEFAULT_NN_VAR_SIZE = 100;

NNVar::NNVar()
{
    _values.resize ( CONST_DEFAULT_NN_VAR_SIZE, 0 );
}

NNVar::NNVar ( float value )
{
    _values.resize ( CONST_DEFAULT_NN_VAR_SIZE, value );
}

float& NNVar::operator [] ( unsigned int index )
{
    if ( index >= _values.size() ) {
        throw nn::NNException ( "Wrong argument index out of bounds", __FILE__, __LINE__);
    }

    return _values[index];
}

NNVar NNVar::operator + ( const NNVar & var ) const
{
    NNVar result;
    for ( unsigned int i = 0; i < CONST_DEFAULT_NN_VAR_SIZE; i++ ) {
        result[i] = var._values.at ( i ) + _values.at ( i );
    }

    return result;
}

NNVar NNVar::operator - ( const NNVar & var ) const
{
    NNVar result;
    for ( unsigned int i = 0; i < _values.size(); i++ ) {
        result[i] = _values.at ( i ) - var._values.at ( i );
    }

    return result;
}

NNVar NNVar::operator * ( const NNVar & var ) const
{
    NNVar result ( boost::numeric_cast<float>(_values.size()) );
    for ( unsigned int i = 0; i < CONST_DEFAULT_NN_VAR_SIZE; i++ ) {
        result[i] = var._values.at ( i ) * _values.at ( i );
    }

    return result;
}

NNVar NNVar::operator / ( const NNVar & var ) const
{
    NNVar result;
    for ( unsigned int i = 0; i < CONST_DEFAULT_NN_VAR_SIZE; i++ ) {
        if ( var._values.at ( i ) == 0 ) {
            throw nn::NNException ( "Wrong division by zero found", __FILE__, __LINE__ );
        }

        result[i] = _values.at ( i ) / var._values.at ( i );
    }

    return result;
}

NNVar NNVar::Pow ( NNVar& value )
{
    NNVar result;
    for ( unsigned int i = 0; i < CONST_DEFAULT_NN_VAR_SIZE; i++ ) {
        result[i] = pow ( _values.at ( i ), value[i] );
    }

    return result;
}

NNVar NNVar::Exp()
{
    NNVar result;
    for ( unsigned int i = 0; i < CONST_DEFAULT_NN_VAR_SIZE; i++ ) {
        result[i] = exp ( _values.at ( i ) );
    }

    return result;
}

NNVar NNVar::Sqrt() const
{
    NNVar var;
    for ( unsigned int i = 0; i < CONST_DEFAULT_NN_VAR_SIZE; i++ ) {
        var[i] = sqrt ( _values[i] );
    }

    return var;
}

const NNVar& NNVar::operator += ( const NNVar & var )
{
    for ( unsigned int i = 0; i < CONST_DEFAULT_NN_VAR_SIZE; i++ ) {
        _values[i] = _values.at ( i ) + var._values.at ( i );
    }

    return *this;
}

bool NNVar::operator > ( const NNVar& var ) const
{
    return GetAverage() > var.GetAverage();
}

bool NNVar::operator < ( const NNVar& var ) const
{
    return GetAverage() < var.GetAverage();
}

float NNVar::GetAverage() const
{
    float sum = 0;
    for ( unsigned int i = 0; i < CONST_DEFAULT_NN_VAR_SIZE; i++ ) {
        sum += _values.at ( i );
    }

    return sum / ( float ( _values.size() ) );
}

NNVar::~NNVar()
{
    // TODO Auto-generated destructor stub
}

NNVar exp ( NNVar& var )
{
    return var.Exp();
}

NNVar sqrt ( const NNVar& var )
{
    return var.Sqrt();
}

NNVar pow ( NNVar& var, NNVar& power )
{
    return var.Pow ( power );
}
